using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using Risiko.State;


namespace Risiko.Logic
{
  public class TaskAIPlayer : PlayerBehavior
  {
    public TaskAIPlayer(Game game)
      : base(game)
    {
      this.EnabledChanged += new EventHandler<EventArgs>(TaskAIPlayer_EnabledChanged);
    }

    public override void Initialize()
    {
      base.Initialize();
    }

    public override void Update(GameTime gameTime)
    {
      base.Update(gameTime);
    }

    void TaskAIPlayer_EnabledChanged(object sender, EventArgs e)
    {
      if (Enabled)
      {
        //hasNextMove = Logic.HasNextMove.Thinking;
        hasNextAttack = Logic.HasNextMove.Thinking;
        //hasStrategicMove = Logic.HasNextMove.No;
        hasConquerMove = Logic.HasNextMove.No;

        num_Attacks = 1;
        //PlaceReinforcements();
        //PlayCardCombination();
        //StartNextAttackAsync();
        //StrategicMove();

        StartAI();
      }
    }

    private void StartAI()
    {
      Async(() =>
      {
        PlayCardCombination();

        Async(() =>
        {
          PlayPlaceReinforcements();

          Async(() =>
          {
            PlayAttacks();

            Async(() =>
            {
              PlayStrategicMove();
            });

          });

        });
        
      });
    }    

    // Play Moves

    private void PlayCardCombination()
    {
      hasCardMove = HasNextMove.Thinking;

      gameState.playerStates[(int)selfID].CurrCardMove = ComputeCardCombinations();

      if (gameState.playerStates[(int)selfID].CurrCardMove.isValid)
      {
        //hasCardMove = HasNextMove.Yes;
        PlayCards(gameState.playerStates[(int)selfID].CurrCardMove);
      }

      hasCardMove = HasNextMove.No;
    }

    private void PlayPlaceReinforcements()
    {
      hasNextMove = HasNextMove.Thinking;

      ComputeReinforcementsPlacement(); // Crea Lista piazzamenti

      for (int i = 0; i < gameState.playerStates[(int)selfID].CurrArmiesPlacements.Count; i++)
      {
        // Esegue piazzamento
        gameState.playerStates[(int)selfID].CurrArmiesPlacement = gameState.playerStates[(int)selfID].CurrArmiesPlacements[i];
        //MakePlacements(gameState.playerStates[(int)selfID].CurrArmiesPlacement);

        gameState.playerStates[(int)selfID].MossaFatta = true;

        while (gameState.playerStates[(int)selfID].MossaFatta) { Thread.Sleep(10); }
        while (!gameState.playerStates[(int)selfID].MossaAnimata) { Thread.Sleep(10); }
        MakePlacement(gameState.playerStates[(int)selfID].CurrArmiesPlacement);
      }

      hasNextMove = HasNextMove.No;
    }

    private void PlayStrategicMove()
    {
      hasStrategicMove = HasNextMove.Thinking;

      //StrategicMoveArmies.from = 
      //StrategicMoveArmies.to = 
      //StrategicMoveArmies.numArmies = 

      //gameState.playerStates[(int)selfID].MossaFatta = true;

      //while (gameState.playerStates[(int)selfID].MossaFatta) { Thread.Sleep(10); }
      //while (!gameState.playerStates[(int)selfID].MossaAnimata) { Thread.Sleep(10); }

      hasStrategicMove = HasNextMove.No;
    }

    private void PlayAttacks()
    {
      hasNextAttack = HasNextMove.Thinking;

      while (num_Attacks > 0)
      {
        ComputeNextAttack();

        conquered = false;
        ApplyAttack();

        // Per dare al Supervisor il tempo di cambiare fase
        Thread.Sleep(100);

        if (conquered)
        {
          // Codice da eseguire in fase di conquista
          hasConquerMove = HasNextMove.Thinking;

          ComputeConquerMove();

          // Attualmente sono Greedy, ma dovrei usare una funzione
          // per calcolare se attaccare ancora
          num_Attacks++;
        }
        else
          num_Attacks = 0;
      }

      hasNextAttack = HasNextMove.No;
    }

    private void ComputeConquerMove()
    {
      Thread.Sleep(1000);
      hasConquerMove = HasNextMove.No;
    }

    // Compute Moves

    private void ComputeStrategicMove() {} 

    public void ComputeReinforcementsPlacement()
    {
      hasNextMove = Logic.HasNextMove.Thinking;

      gameState.playerStates[(int)selfID].CurrArmiesPlacements.Clear();           

      gameState.board.IterTerritories(t =>
        {
          if (t.owner == selfID)
          {
            if (gameState.playerStates[(int)selfID].reinforcementsNum > 0)
            {
              var placement = new ArmiesPlacement() { territory = t, numArmies = 1 };
              gameState.playerStates[(int)selfID].CurrArmiesPlacements.Add(placement);
              gameState.playerStates[(int)selfID].reinforcementsNum--;
            }
          }
        });

      hasNextMove = Logic.HasNextMove.Yes;
    }

    public Attack nextAttack;
    private int num_Attacks = 0;
    private void ComputeNextAttack()
    {
      //if (num_Attacks != 1)
      //{
      //  hasNextAttack = Logic.HasNextMove.No;
      //  return;
      //}

      //List<State.Territory> territories = new List<State.Territory>();
      //gameState.board.IterTerritories(t =>
      //  {
      //    if (t.owner == selfID)
      //      territories.Add(t);
      //  });

      //new Thread(() =>
      //{
        Thread.Sleep(1000);
        //for (int i = 0; i < territories.Count; i++)
        for (int i = 0; i < gameState.playerStates[(int)selfID].OwnedTerritories.Count; ++i)
        {
          var t = gameState.board.GetTerritory(gameState.playerStates[(int)selfID].OwnedTerritories[i]); //territories[i];

          if (t.armies >= 2)
            for (int j = 0; j < t.neighbors.Length; j++)
            {
              int ArmiesAttack = 1;
              if (t.armies == 3) ArmiesAttack = 2;
              if (t.armies > 3) ArmiesAttack = 3;

              var n = t.neighbors[j];
              var t1 = gameState.board.GetTerritory(n);
              if (t1.owner != selfID)
              {
                nextAttack = new Attack()
                {
                  from = new State.TerritoryReference() { continentID = t.continentID, territoryID = t.territoryID },
                  to = new State.TerritoryReference() { continentID = t1.continentID, territoryID = t1.territoryID },
                  numArmies = ArmiesAttack
                };

                gameState.playerStates[(int)selfID].CurrAttack = nextAttack;
                gameState.playerStates[(int)selfID].MossaFatta = true;

                //hasNextAttack = Logic.HasNextMove.Yes;
                
                return;
              }
            }
          //Thread.Sleep(10);
        }

        //hasNextAttack = Logic.HasNextMove.No;
        //return;
      //}).Start();
    }

    public override void OnCurrentAttackWon()
    {
      hasNextAttack = HasNextMove.Thinking;

      num_Attacks = 1;
      //PlayAttack();
      ComputeNextAttack();
      base.OnCurrentAttackWon();
    }

    public override void OnCurrentAttackLost()
    {
      hasNextAttack = HasNextMove.Thinking;

      hasNextAttack = HasNextMove.No;
      num_Attacks++;
      //ComputeNextAttack();
    }
  }
}
